package android.arch.lifecycle

/**
 * Created by yml on 2013/10/23.
 * 这个类必须定义在 androidx.lifecycle 包名下才能使用 MutableLiveData 的一些方法。
 * 也是结合 ai.moqi.fingerprint.ktbus 中的功能来使用。
 */
open class ExternalLiveDataKt<T> : MutableLiveData<T>() {

    override fun observe(owner: LifecycleOwner, observer: Observer<T>) {
        if (owner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
            // ignore
            return
        }
        val wrapper = ExternalLifecycleBoundObserver(owner, observer)
        val existing: LiveData<*>.LifecycleBoundObserver? = callMethodPutIfAbsent(observer, wrapper) as LiveData<*>.LifecycleBoundObserver?
        require(!(existing != null && !existing.isAttachedTo(owner))) {
            ("Cannot add the same observer with different lifecycles")
        }
        if (existing != null) {
            return
        }
        owner.lifecycle.addObserver(wrapper)
    }

    public override fun getVersion(): Int {
        return super.getVersion()
    }

    /**
     * determine when the observer is active, means the observer can receive message
     * the default value is CREATED, means if the observer's state is above create,
     * for example, the onCreate() of activity is called
     * you can change this value to CREATED/STARTED/RESUMED
     * determine on witch state, you can receive message
     *
     * @return Lifecycle.State
     */
    protected open fun observerActiveLevel(): Lifecycle.State? {
        return Lifecycle.State.CREATED
    }

    internal inner class ExternalLifecycleBoundObserver(
        owner: LifecycleOwner,
        observer: Observer<T>?
    ) : LifecycleBoundObserver(owner, observer) {
        public override fun shouldBeActive(): Boolean {
            return mOwner.lifecycle.currentState.isAtLeast(observerActiveLevel()!!)
        }
    }

    @get:Throws(Exception::class)
    private val fieldObservers: Any
        private get() {
            val fieldObservers = LiveData::class.java.getDeclaredField("mObservers")
            fieldObservers.isAccessible = true
            return fieldObservers[this]
        }

    // 反射调用 LiveData.mObservers 这个map对象的 putIfAbsent() 方法
    @Throws(Exception::class)
    private fun callMethodPutIfAbsent(observer: Any, wrapper: Any): Any? {
        val mObservers = fieldObservers
        val classOfSafeIterableMap: Class<*> = mObservers.javaClass
        val putIfAbsent = classOfSafeIterableMap.getDeclaredMethod(
            "putIfAbsent",
            Any::class.java, Any::class.java
        )
        putIfAbsent.isAccessible = true
        return putIfAbsent.invoke(mObservers, observer, wrapper)
    }

    companion object {
        const val START_VERSION = LiveData.START_VERSION
    }
}